package com.yyfax.pay.third.facade.baofu;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yyfax.commons.http.HttpUtil;
import com.yyfax.commons.json.JacksonUtil;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.exception.YYPayException;
import com.yyfax.pay.common.util.BaoFuUtils;
import com.yyfax.pay.third.model.to.baofu.PayinBatchOrderBaoFuContent;
import com.yyfax.pay.third.model.to.baofu.PayinBatchOrderBaoFuParams;
import com.yyfax.pay.third.model.to.baofu.PayinBatchOrderBaoFuParams.PayinBatchItem;
import com.yyfax.pay.third.model.to.baofu.PayinOrderBaoFuContent;
import com.yyfax.pay.third.model.to.baofu.PayinOrderBaoFuParams;
import com.yyfax.pay.third.model.to.baofu.QueryPayinBatchOrderBaoFuContent;
import com.yyfax.pay.third.model.to.baofu.QueryPayinBatchOrderBaoFuContent.QueryPayinBatchContentItem;
import com.yyfax.pay.third.model.to.baofu.QueryPayinBatchOrderBaoFuParams;
import com.yyfax.pay.third.model.to.baofu.QueryPayinOrderBaoFuContent;
import com.yyfax.pay.third.model.to.baofu.QueryPayinOrderBaoFuParams;

@Service
public class BaoFuApi {

	private Logger logger = LoggerFactory.getLogger(getClass());

	public PayinOrderBaoFuContent payin(PayinOrderBaoFuParams params) throws Exception {
		final String OP = "【payin】【BAOFU】 代扣";
		try{
			PayinOrderBaoFuContent content = new PayinOrderBaoFuContent();
			Map<String,String> headPostParam = new HashMap<String,String>();
			
			headPostParam.put("version", params.getVersion());
			headPostParam.put("member_id", params.getMemberId());
			headPostParam.put("terminal_id", params.getTerminalId());
			headPostParam.put("txn_type", params.getTxnType());
			headPostParam.put("txn_sub_type", params.getTxnSubType());
			headPostParam.put("data_type", params.getDataType());
	        String  pfxpath = params.getPfxPath();//商户私钥        
	        String  cerpath = params.getCerPath();//宝付公钥
	        Map<String,String> XMLArray = new HashMap<String,String>();
	     
	        XMLArray.put("txn_sub_type", params.getTxnSubType());
	        XMLArray.put("biz_type", params.getBizType());
	        XMLArray.put("terminal_id", params.getTerminalId());
	        XMLArray.put("member_id", params.getMemberId());
	        XMLArray.put("trans_serial_no", params.getTransSerialNo());
	        XMLArray.put("trade_date", params.getTradeDate());
//	        XMLArray.put("additional_info", "附加信息");
//	        XMLArray.put("req_reserved", "保留");
	        
	      	
    		XMLArray.put("pay_code", params.getPayCode());
            XMLArray.put("pay_cm", params.getPayCm());
            XMLArray.put("id_card_type", params.getIdCardType());
            XMLArray.put("acc_no", params.getAccNo());
            XMLArray.put("id_card", params.getIdCard());
            XMLArray.put("id_holder", params.getIdHolder());
            XMLArray.put("mobile", params.getMobile());
//	        XMLArray.put("valid_date", valid_date);
//	        XMLArray.put("valid_no", );
            XMLArray.put("trans_id", params.getTransId());
            XMLArray.put("txn_amt", params.getTxnAmt());        	
	        

		    String XmlOrJson = JSONObject.toJSONString(XMLArray);
	        
			String base64str = BaoFuUtils.Base64Encode(XmlOrJson);
			String data_content = BaoFuUtils.encryptByPriPfxFile(base64str,pfxpath,params.getPfxPwd());	
	        
			headPostParam.put("data_content", data_content);
	        
			logger.debug(OP + "请求信息:{}{}", params.getMemberId(), headPostParam);
			String respStr = HttpUtil.post(params.getUrl(), headPostParam);
			logger.info(OP + "返回信息解密前:{}{}", params.getMemberId(), respStr);
			
			respStr = BaoFuUtils.decryptByPubCerFile(respStr,cerpath);
			
			if (StringUtils.isBlank(respStr)) {
				logger.error(OP + "失败{}", params.getMemberId());
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "代扣失败");
			} 
			
			respStr = BaoFuUtils.Base64Decode(respStr);		 
			logger.info(OP + "返回信息解密后:{}{}", params.getMemberId(), respStr);
		
			content = JSONObject.toJavaObject(JSONObject.parseObject(respStr), PayinOrderBaoFuContent.class);
			content.setReqContent(JacksonUtil.nonullMapper.toJson(headPostParam));
			return content;
		}catch(Exception e){
			logger.error(OP +"失败", e);
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "批量代扣失败");
		}
	}
	
	public PayinBatchOrderBaoFuContent batchPayin(PayinBatchOrderBaoFuParams params) throws Exception {
		final String OP = "【batchPayin】【BAOFU】 批量代扣";
		try{
			PayinBatchOrderBaoFuContent content = new PayinBatchOrderBaoFuContent();
			Map<String, Object> dataMap = new HashMap<String, Object>();// 主体参数
			dataMap.put("terminal_id", params.getTerminalId());
			dataMap.put("member_id", params.getMemberId());
			dataMap.put("txn_sub_type", params.getTxnSubType());
			dataMap.put("trans_batch_id", params.getTransBatchId());
			dataMap.put("trans_serial_no", params.getTransSerialNo());
	
			Map<String, Object> infomap = new HashMap<String, Object>();
			infomap.put("info", buildPayinBatchOrderInfo(params.getItems()));
			dataMap.put("actual_info", infomap);// JSON样式
			String jsonData = JSONObject.toJSONString(dataMap);
	
			byte[] gZipStr = BaoFuUtils.gZip(jsonData.getBytes("UTF-8"));// 先压缩数据
	
			String dataContent = BaoFuUtils.encryptByPriPfxFile(gZipStr, params.getPfxPath(), params.getPfxPwd()); // 再RSA
	
			Map<String, String> headPostParam = new HashMap<String, String>();
			headPostParam.put("version", params.getVersion());
			headPostParam.put("member_id", params.getMemberId());
			headPostParam.put("terminal_id", params.getTerminalId());
			headPostParam.put("txn_type", params.getTxnType());// 交易子类
			headPostParam.put("txn_sub_type", params.getTxnSubType());
			headPostParam.put("data_type", params.getDataType());
			headPostParam.put("data_content", dataContent);
	
			logger.debug(OP + "请求信息:{}{}", params.getMemberId(), headPostParam);
			String respStr = HttpUtil.post(params.getUrl(), headPostParam);
			logger.info(OP + "返回信息解密前:{}{}", params.getMemberId(), respStr);
			if (StringUtils.isBlank(respStr)) {
				logger.error(OP + "失败{}", params.getMemberId());
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "批量代扣失败");
			} 
			byte[] PostStringByte = BaoFuUtils.decryptByPubCerFileByte(respStr, params.getCerPath());
			respStr = new String(BaoFuUtils.unZip(PostStringByte), "UTF-8");
			logger.info(OP + "返回信息解密后:{}{}", params.getMemberId(), respStr);
	
			content = JSONObject.toJavaObject(JSONObject.parseObject(respStr), PayinBatchOrderBaoFuContent.class);
			content.setReqContent(JacksonUtil.nonullMapper.toJson(headPostParam));
			return content;
		}catch(Exception e){
			logger.error(OP +"失败", e);
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "批量代扣失败");
		}
	}
	
	public QueryPayinBatchOrderBaoFuContent queryBatchPayin(QueryPayinBatchOrderBaoFuParams params) throws Exception{
		final String OP = "【queryBatchPayin】【BAOFU】 代扣批量查询";
		try{
			QueryPayinBatchOrderBaoFuContent content = new QueryPayinBatchOrderBaoFuContent();
			Map<String, Object> dataMap = new HashMap<String, Object>();// 主体参数
			dataMap.put("terminal_id", params.getTerminalId());
			dataMap.put("member_id", params.getMemberId());
			dataMap.put("txn_sub_type", params.getTxnSubType());
			dataMap.put("trans_batch_id", params.getTransBatchId());
			dataMap.put("trans_serial_no", params.getTransSerialNo());
	
			String jsonData = JSONObject.toJSONString(dataMap);
	
			byte[] gZipStr = BaoFuUtils.gZip(jsonData.getBytes("UTF-8"));// 先压缩数据
	
			String dataContent = BaoFuUtils.encryptByPriPfxFile(gZipStr, params.getPfxPath(), params.getPfxPwd()); // 再RSA
	
			Map<String, String> headPostParam = new HashMap<String, String>();
			headPostParam.put("version", params.getVersion());
			headPostParam.put("member_id", params.getMemberId());
			headPostParam.put("terminal_id", params.getTerminalId());
			headPostParam.put("txn_type", params.getTxnType());// 交易子类
			headPostParam.put("txn_sub_type", params.getTxnSubType());
			headPostParam.put("data_type", params.getDataType());
			headPostParam.put("data_content", dataContent);
	
			logger.debug(OP + "请求信息:{}{}", params.getMemberId(), headPostParam);
			String respStr = HttpUtil.post(params.getUrl(), headPostParam);
			logger.info(OP + "信息解密前:{}{}", params.getMemberId(), respStr);
			byte[] postStringByte = BaoFuUtils.decryptByPubCerFileByte(respStr, params.getCerPath());
			respStr = new String(BaoFuUtils.unZip(postStringByte), "UTF-8");
			logger.info(OP +"信息解密后:{}{}", params.getMemberId(), respStr);
	
			content = transformResult(respStr);
			content.setReqContent(JacksonUtil.nonullMapper.toJson(headPostParam));
	
			return content;
		}catch(Exception e){
			logger.error(OP +"失败", e);
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), OP + "失败"); 
		}
	}
	
	private QueryPayinBatchOrderBaoFuContent transformResult(String respStr){
		JSONObject json = JSONObject.parseObject(respStr);
		QueryPayinBatchOrderBaoFuContent content = JSONObject.toJavaObject(json, QueryPayinBatchOrderBaoFuContent.class);
		Map m = (Map)json.get("actual_info");
		List<String> infoLs = (List)m.get("info");
		List<QueryPayinBatchContentItem> items = Lists.newArrayList();
		for(String info : infoLs){
			List<String> itemData = Splitter.on(QueryPayinBatchContentItem.ENCRYPTSEPERATOR).splitToList(info);
			QueryPayinBatchContentItem item = new QueryPayinBatchContentItem();
			item.setTransId(itemData.get(0));
			item.setOrderStat(itemData.get(1));
			item.setRespCode(itemData.get(2));
			item.setRespMsg(itemData.get(3));
			item.setTransNo(itemData.get(4));
			item.setSuccAmt(itemData.get(5));
			item.setReqReserved(itemData.get(6));
			items.add(item);
		}
		content.setItems(items);
		return content;
	}
	
	public QueryPayinOrderBaoFuContent queryPayinOrder(QueryPayinOrderBaoFuParams params)throws Exception{
		final String OP = "【queryPayinOrder】【BAOFU】 代扣查询";
		try{
			QueryPayinOrderBaoFuContent content = new QueryPayinOrderBaoFuContent();
			Map<String,String> headPostParam = new HashMap<String,String>();
			
			headPostParam.put("version", params.getVersion());
			headPostParam.put("member_id", params.getMemberId());
			headPostParam.put("terminal_id", params.getTerminalId());
			headPostParam.put("txn_type", params.getTxnType());
			headPostParam.put("txn_sub_type", params.getTxnSubType());
			headPostParam.put("data_type", params.getDataType());
	        String  pfxpath = params.getPfxPath();//商户私钥        
	        String  cerpath = params.getCerPath();//宝付公钥
	        Map<String,String> XMLArray = new HashMap<String,String>();
	     
	        XMLArray.put("txn_sub_type", params.getTxnSubType());
	        XMLArray.put("biz_type", params.getBizType());
	        XMLArray.put("terminal_id", params.getTerminalId());
	        XMLArray.put("member_id", params.getMemberId());
	        XMLArray.put("trans_serial_no", params.getTransSerialNo());
	        XMLArray.put("orig_trade_date", params.getOrigTradeDate());
//	        XMLArray.put("additional_info", "附加信息");
//	        XMLArray.put("req_reserved", "保留");
	        
	      	
	        XMLArray.put("orig_trans_id", params.getOrigTransId());      	
	        

		    String XmlOrJson = JSONObject.toJSONString(XMLArray);
	        
			String base64str = BaoFuUtils.Base64Encode(XmlOrJson);
			String data_content = BaoFuUtils.encryptByPriPfxFile(base64str,pfxpath,params.getPfxPwd());	
	        
			headPostParam.put("data_content", data_content);
	        
			logger.debug(OP + "请求信息:{}{}", params.getMemberId(), headPostParam);
			String respStr = HttpUtil.post(params.getUrl(), headPostParam);
			logger.info(OP + "返回信息解密前:{}{}", params.getMemberId(), respStr);
			
			respStr = BaoFuUtils.decryptByPubCerFile(respStr,cerpath);
			
			if (StringUtils.isBlank(respStr)) {
				logger.error(OP + "失败{}", params.getMemberId());
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "代扣失败");
			} 
			
			respStr = BaoFuUtils.Base64Decode(respStr);		 
			logger.info(OP + "返回信息解密后:{}{}", params.getMemberId(), respStr);
		
			content = JSONObject.toJavaObject(JSONObject.parseObject(respStr), QueryPayinOrderBaoFuContent.class);
			content.setReqContent(JacksonUtil.nonullMapper.toJson(headPostParam));
			return content;
		}catch(Exception e){
			logger.error(OP +"失败", e);
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_BATCH_PAYIN_FAIL.getValue(), "批量代扣失败");
		}
	}

	private List<String> buildPayinBatchOrderInfo(List<PayinBatchItem> items) {
		List<String> info = Lists.newArrayList();
		// TODO mobile和reqReserved虽然文档上说为可选，但实际为空会报错，而且现在通道不支持，等待后续解决 
		for (PayinBatchItem item : items) {
			info.add(Joiner
					.on(PayinBatchItem.ENCRYPTSEPERATOR)
					.skipNulls()
					.join(item.getTransId(), item.getTransDate(), item.getAccNo(), item.getIdHolder(), item.getIdCardType(), item.getIdCard(),
							item.getMobile(), item.getTxnAmt(), item.getReqReserved() == null ?"保留字段":item.getReqReserved()));

		}
		return info;
	}


}
